import { message } from "@/utils/message";
import { ref, onMounted } from "vue";

export function useSerial() {
  /////////////////串口相关/////////////////

  const serialOpenRef = ref<Boolean>(); //串口目前是打开状态
  const serialCloseRef = ref<Boolean>(); //串口目前是手动关闭状态
  const serialPortRef = ref<any>();
  const readerRef = ref<any>();
  const serialDataRef = ref<Array<any>>([]); //串口缓存数据
  const serialTimerRef = ref<any>(); //串口分包合并时钟

  //关闭串口
  const closeSerial = async () => {
    if (serialOpenRef.value) {
      serialOpenRef.value = false;
      readerRef.value?.cancel();
    }
  };

  //打开串口
  const openSerial = () => {
    const SerialOptions = {
      baudRate: 9600,
      dataBits: 8,
      stopBits: 1,
      parity: "none"
    };

    serialPortRef.value
      .open(SerialOptions)
      .then(() => {
        serialOpenRef.value = true;
        serialCloseRef.value = false;
        readData();
      })
      .catch(e => {
        console.log("打开串口失败:" + e.toString());
        message("打开串口失败:" + e.toString(), { type: "error" });
      });
  };

  const writeData = async data => {
    if (!serialPortRef.value || !serialPortRef.value.writable) {
      console.log("请先打开串口再发送数据");
      message("请先打开串口再发送数据", { type: "error" });
      return;
    }
    const writer = serialPortRef.value.writable.getWriter();
    data = new Uint8Array([...data, 0x0d, 0x0a]); //末尾自动添加换行
    await writer.write(data);
    writer.releaseLock();
    console.log(data, false);
    addLog(data, false);
  };

  //读串口数据
  const readData = async () => {
    while (serialOpenRef.value && serialPortRef.value.readable) {
      readerRef.value = serialPortRef.value.readable.getReader();
      try {
        // eslint-disable-next-line no-constant-condition
        while (true) {
          const { value, done } = await readerRef.value.read();
          if (done) {
            break;
          }
          dataReceived(value);
        }
      } catch (error) {
        console.log(error);
      } finally {
        readerRef.value.releaseLock();
      }
    }
    await serialPortRef.value.close();
  };

  //串口分包合并
  const dataReceived = data => {
    serialDataRef.value.push(...data);
    // if (toolOptions.timeOut == 0) {
    //   // addLog(serialData, true);
    //   serialDataRef.value.splice(0);
    //   return;
    // }
    //清除之前的时钟
    clearTimeout(serialTimerRef.value);
    serialTimerRef.value = setTimeout(() => {
      //超时发出
      addLog(serialDataRef.value, true);
      serialDataRef.value.splice(0);
    }, 50);
  };

  const sendHex = async hex => {
    const value = hex.replace(/\s+/g, "");
    if (/^[0-9A-Fa-f]+$/.test(value) && value.length % 2 === 0) {
      const data = [];
      for (let i = 0; i < value.length; i = i + 2) {
        data.push(parseInt(value.substring(i, i + 2), 16));
      }
      await writeData(Uint8Array.from(data));
    } else {
      console.log("HEX格式错误:" + hex);
      message("HEX格式错误:" + hex, { type: "error" });
    }
  };
  ////////////以下按钮控制事件

  onMounted(() => {
    if ("serial" in navigator) {
      navigator.serial.addEventListener("connect", event => {
        // TODO: 自动打开事件。目标器或警告用户端口可用。
        console.log("connect:" + JSON.stringify(event));
        // serialStatuChange(true);
        serialPortRef.value = event.target;
        //未主动关闭连接的情况下,设备重插,自动重连
        if (!serialCloseRef.value) {
          openSerial();
        }
      });

      navigator.serial.addEventListener("disconnect", event => {
        // TODO: Remove |event.target| from the UI. {"isTrusted":true}
        // 如果打开了串行端口，还会观察到流错误。
        console.log("disconnect:" + JSON.stringify(event));
        // serialStatuChange(false);
        setTimeout(closeSerial, 500);
      });
    } else {
      console.log("你的浏览器不支持串口连接");
      message("你的浏览器不支持串口连接", { type: "error" });
    }
  });

  //选择串口
  async function selectBtn() {
    // 客户端授权
    if ("serial" in navigator) {
      try {
        await navigator.serial.requestPort().then(async port => {
          //关闭旧的串口
          serialPortRef.value?.close();
          await serialPortRef.value?.forget();
          serialPortRef.value = port;
          // serialStatuChange(true);
        });
      } catch (e) {
        console.error("获取串口权限出错" + e.toString());
        message("获取串口权限出错:" + e.toString(), { type: "error" });
      }
    } else {
      console.log("你的浏览器不支持串口连接");
      message("你的浏览器不支持串口连接", { type: "error" });
    }
  }
  //打开或关闭串口
  function openBtn() {
    if (!serialPortRef.value) {
      console.log("请先选择串口");
      message("请先选择串口", { type: "error" });
      return;
    }
    openSerial();
  }

  function closeBtn() {
    if (!serialPortRef.value) {
      console.log("请先选择串口");
      message("请先选择串口", { type: "error" });
      return;
    }
    if (serialPortRef.value.writable && serialPortRef.value.readable) {
      closeSerial();
      serialCloseRef.value = true;
    }
  }

  function connectBtn() {
    sendHex("02 0b 0f");
  }

  function openICCartBtn() {
    sendHex("12 F2 05 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70");
  }

  function closeICCartBtn() {
    sendHex("12 F2 05 71 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70");
  }

  function initICCartBtn() {
    sendHex("02 F1 05");
  }

  const serialLogsRef = ref<any>();
  function addLog(data, isReceive = true) {
    let form = "→";
    if (isReceive) {
      form = "←";
    }
    let newmsg = "";
    const dataHex = [];
    for (const d of data) {
      //转16进制并补0
      dataHex.push(("0" + d.toString(16).toLocaleUpperCase()).slice(-2));
    }
    newmsg += "HEX:" + form + "\n";
    newmsg += dataHex.join(" ") + "\n";
    if (serialLogsRef.value) {
      serialLogsRef.value = serialLogsRef.value + newmsg;
    } else {
      serialLogsRef.value = newmsg;
    }
  }
  return {
    serialLogsRef,
    selectBtn,
    openBtn,
    closeBtn,
    connectBtn,
    openICCartBtn,
    closeICCartBtn,
    initICCartBtn
  };
}
